﻿using Abide_AddOn_API;
using Abide_AddOn_API.Classes;
using Abide_AddOn_API.Interfaces;
using Abide_Halo_Library;
using Abide_Halo_Library.Halo_2_Beta_Map;
using Potential_Software.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace Abide.UI_Elements.Halo_2_Beta
{
    [ToolboxItem(false)]
    public partial class MapControl : UserControl
    {
        public Halo2BetaMap Map
        {
            get;
            protected set;
        }
        public Classes.AbideAddOnManager Manager
        {
            get;
            protected set;
        }
        public List<IAddOn> AddOns
        {
            get;
            protected set;
        }
        public List<TabPage> TabPages
        {
            get;
            protected set;
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            Uxtheme.SetWindowTheme(TagView.Handle, "explorer", null);
        }
        public MapControl(string FileLocation)
        {
            InitializeComponent();
            TagView.ContextMenu = TagViewContextMenu;

            if (!Settings.UseTagViewIcons)
            {
                TagView.ImageList = null;
            }

            //Prepare Images...
            this.TagViewImgList.Images.Add(new Icon(Properties.Resources.Unknown_Map, 16, 16));
            this.TagViewImgList.Images.Add(new Icon(Properties.Resources.Folder, 16, 16));
            this.TagViewImgList.Images.Add(new Icon(Properties.Resources.Abide_Reference, 16, 16));
            this.TagViewImgList.Images.Add(new Icon(Properties.Resources.Bitmap, 16, 16));
            this.TagViewImgList.Images.Add(new Icon(Properties.Resources.Sound, 16, 16));
            this.TagViewImgList.Images.Add(new Icon(Properties.Resources.BSP, 16, 16));
            this.TagViewImgList.Images.Add(new Icon(Properties.Resources.New_HUD_Interface, 16, 16));

            //Prepare for Xbox
            Program.XboxChanged += Program_XboxChanged;

            //Load Map
            Map = new Halo2BetaMap();
            Map.BeginLoadMap(MapLoaded, FileLocation, null);
        }

        private void MapLoaded(IAsyncResult ar)
        {
            //End
            Map.EndLoadMap(ar);

            //Initialize Manager
            Manager = new Classes.AbideAddOnManager(this, Map);
            Manager.ReloadMap += Manager_ReloadMap;
            TabPages = new List<TabPage>();
            AddOns = new List<IAddOn>();

            //Invoke... ?
            if (InvokeRequired) Invoke(new MethodInvoker(delegate
            {
                //Check...
                if (ParentForm != null)
                    ParentForm.Text = Map.MapName;

                //Load Tags...
                UpdateTagView();

                //Apply AddOns
                ApplyAddOns();
            }));
            else
            {
                //Check...
                if (ParentForm != null)
                    ParentForm.Text = Map.MapName;

                //Load Tags...
                UpdateTagView();

                //Apply AddOns
                ApplyAddOns();
            }
        }
        private void Loaded()
        {
            //Check...
            if (ParentForm != null)
                ParentForm.Text = Map.MapName;

            //Clear
            TabPages = new List<TabPage>();

            //Load Tags...
            UpdateTagView();

            //Apply AddOns
            ApplyAddOns();
        }
        private void Manager_ReloadMap(object sender, EventArgs e)
        {
            //Begin
            Map.BeginReload(MapReloaded, null);
        }
        private void Program_XboxChanged(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }
        private void TagView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Tag != null)
            {
                //Get Tag?
                int TagInt = int.Parse(e.Node.Tag.ToString());

                if (TagInt == -1)
                    PropertyView.SelectedObject = Map;
                else
                {
                    //Load Tag
                    PropertyView.SelectedObject = Map.GetEntryByIdent(TagInt);
                    LoadTag(Map.GetEntryByIdent(TagInt));
                }
            }
        }
        private void LoadTag(IndexEntry indexEntry)
        {
            //Update
            Manager.SetEntry(indexEntry);

            //Update AddOns
            foreach (var addOn in AddOns)
            {
                //Change
                try { addOn.API.ChangeIndexEntry(); }
                catch (Exception ex) { ReportAddOnError(addOn, ex, "TAG_CHANGED"); }
                finally { if (Map.IO.Open) Map.IO.CloseIO(); }
            }

            //Update Tab View
            foreach (TabPage page in TabPages)
            {
                //Get ITabPage
                var Interface = (ITabPage)page.Tag;

                //Get Types
                string[] types = Interface.Filter.Split('|');
                bool Contains = Interface.Filter == "*";
                foreach (string type in types)
                    Contains |= (indexEntry.Class.Trim().ToUpper()) == (type.Trim().ToUpper());

                //Check
                if (Contains)
                {
                    //Add?
                    if (PropertyTabView.TabPages[Interface.Name] == null)
                    {
                        PropertyTabView.TabPages.Add(page);
                        PropertyTabView.SelectedTab = page;
                    }
                }
                else
                    //Remove
                    PropertyTabView.TabPages.Remove(page);
            }
        }
        private void MapReloaded(IAsyncResult ar)
        {
            //Check
            if (InvokeRequired)
                Invoke(new AsyncCallback(MapReloaded), ar);
            else
            {
                //End
                Map.Reload();

                //Initialize Manager
                Manager = new Classes.AbideAddOnManager(this, Map);
                Manager.ReloadMap += Manager_ReloadMap;

                //Load
                Loaded();
            }
        }

        private void TagClassItem_Click(object sender, EventArgs e)
        {
            Settings.TagViewType_H2B = "TagType";
            TagPathItem.Checked = false;
            TagClassItem.Checked = true;
            UpdateTagView();
        }
        private void TagPathItem_Click(object sender, EventArgs e)
        {
            Settings.TagViewType_H2B = "TagPath";
            TagPathItem.Checked = true;
            TagClassItem.Checked = false;
            UpdateTagView();
        }
        private void LoadAddOnItem_Click(object sender, EventArgs e)
        {
            using (FileDialog OpenDlg = new OpenFileDialog())
            {
                OpenDlg.Title = "Open AddOn Assembly";
                OpenDlg.Filter = "Abide AddOn Assemblies (*.dll;*.exe)|*.dll;*.exe";

                if (OpenDlg.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        //Get Names
                        string directoryName = Path.GetDirectoryName(OpenDlg.FileName);
                        string safeName = Path.GetFileName(directoryName);

                        //Load Assembly
                        Classes.AbideAddOnManager.LoadAssembly(safeName, directoryName, OpenDlg.FileName);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.StackTrace);
                    }
                    finally { ApplyAddOns(); }
                }
            }
        }

        private void OpenFolderItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start(Program.AddOnsPath);
        }
        private string ParsePluginPath(string TagClass)
        {
            return Settings.H2B_PluginsPath + "\\" + TagClass.Replace("<", "_").Replace(">", "_").Replace(" ", string.Empty) + ".ent";
        }
        private void UpdateTagView()
        {
            //Begin Update...
            TagView.BeginUpdate();

            //Clear
            TagView.Nodes.Clear();

            //Create...
            TreeNode MapNode = new TreeNode(Map.MapName);
            MapNode.Tag = -1;

            //Get TagView Type
            if (Settings.TagViewType_H2B == "TagType")
            {
                //Add Nodes...
                Map.BuildTreeNodes(ref MapNode, Abide_Halo_Library.Windows.Forms.TagSorting.Class);
                TagPathItem.Checked = false;
                TagClassItem.Checked = true;

            }
            else if (Settings.TagViewType_H2B == "TagPath")
            {
                //Add Nodes...
                Map.BuildTreeNodes(ref MapNode, Abide_Halo_Library.Windows.Forms.TagSorting.Hierarchical);
                TagPathItem.Checked = true;
                TagClassItem.Checked = false;
            }
            else
            {
                //Show Message
                MessageBox.Show("We don't know how to disply your tags, so we're going to default to Tag Type display type.",
                    "Whoops!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                //Add Nodes...
                Map.BuildTreeNodes(ref MapNode, Abide_Halo_Library.Windows.Forms.TagSorting.Class);
                TagPathItem.Checked = false;
                TagClassItem.Checked = true;
            }

            //Prepare
            MapNode.Expand();
            TagView.Nodes.Add(MapNode);

            //Sort
            TagView.Sort();

            //Select
            TagView.SelectedNode = MapNode;

            //End Update...
            TagView.EndUpdate();
        }
        private void ApplyAddOns()
        {
            //Suspend
            SuspendLayout();

            //Store Count
            int ToolCount = 0, TabPageCount = 0, MenuButtonCount = 0;

            //Clear
            AddOns = new List<IAddOn>();
            MetaToolStrip.Items.Clear();
            MetaPanel.Controls.Clear();
            PropertyTabView.TabPages.Clear();
            ToolsDropdownButton.DropDownItems.Clear();

            //Add Tools Base Items
            ToolsDropdownButton.DropDownItems.Add(AddOnsItem);
            ToolsDropdownButton.DropDownItems.Add(ToolSeparator1);
            ToolsDropdownButton.DropDownItems.Add(HistoryItem);

            //Add Base Items
            PropertyTabView.TabPages.Add(PropertyTab);
            MetaToolStrip.Items.Add(ToolsDropdownButton);
            MetaToolStrip.Items.Add(MapLabel);
            MetaToolStrip.Items.Add(ErrorsDropDownButton);

            //Prepare
            DateTime InitTime;

            //Loop through each...
            foreach (KeyValuePair<string, AddOnFactory> CollectionKeyValue in Classes.AbideAddOnManager.Collections)
            {
                //Get Collection
                AddOnFactory Factory = CollectionKeyValue.Value;

                //Handle Tools
                foreach (KeyValuePair<string, List<string>> collection in Factory.Tools)
                    foreach (var typeName in collection.Value)
                    {
                        //Get Interface
                        ITool Tool = Factory.CreateInstance<ITool>(collection.Key, typeName);

                        //Check
                        if (Tool != null)
                        {
                            //Check Abide Version
                            if (Tool.MapVersion == MapVersion.Halo_2b && Classes.AbideAddOnManager.VersionMatch(Tool))
                            {
                                //Write
                                Console.WriteLine("Initializing Tool: {0}...", typeName);
                                InitTime = DateTime.Now;

                                //Initialize
                                try { Tool.Initialize(Manager); }
                                catch (Exception ex) { ReportAddOnError(Tool, ex, "INITIALZE"); }
                                Tool.NameChanged += AddOn_PropertyChanged;
                                Tool.IconChanged += AddOn_PropertyChanged;
                                Tool.DescriptionChanged += AddOn_PropertyChanged;

                                //Write
                                Console.WriteLine("Complete! ({0}ms)", (DateTime.Now - InitTime).Milliseconds);

                                //Add
                                AddOns.Add(Tool);
                                ToolCount++;

                                //Create ToolButton
                                ToolStripMenuItem ToolItem = new ToolStripMenuItem(Tool.Name);
                                ToolItem.ToolTipText = string.Format("{0} v{1} by {2}\r\n{3}", Tool.Name, Tool.Version, Tool.Author, Tool.Description);
                                ToolItem.Image = Tool.Icon;
                                ToolItem.Click += ToolItem_Click;
                                ToolItem.Tag = Tool;

                                //Add
                                ToolsDropdownButton.DropDownItems.Add(ToolItem);
                            }
                            else
                                Tool.Dispose();
                        }
                    }

                //Handle Tab Pages
                foreach (KeyValuePair<string, List<string>> collection in Factory.TabPages)
                    foreach (var typeName in collection.Value)
                    {
                        //Get Interface
                        ITabPage Page = Factory.CreateInstance<ITabPage>(collection.Key, typeName);

                        //Check
                        if (Page != null)
                        {
                            //Check Abide Version
                            if (Page.MapVersion == MapVersion.Halo_2b && Classes.AbideAddOnManager.VersionMatch(Page))
                            {
                                //Write
                                Console.WriteLine("Initializing Tab Page: {0}...", typeName);
                                InitTime = DateTime.Now;

                                //Initialize
                                try { Page.Initialize(Manager); }
                                catch (Exception ex) { ReportAddOnError(Page, ex, "INITIALZE"); }
                                Page.NameChanged += AddOn_PropertyChanged;

                                //Write
                                Console.WriteLine("Complete! ({0}ms)", (DateTime.Now - InitTime).Milliseconds);

                                //Add
                                AddOns.Add(Page);
                                TabPageCount++;

                                //Create
                                TabPage TabPageItem = new TabPage(Page.Name);
                                TabPageItem.Controls.Add(Page.Interface);
                                TabPageItem.Name = Page.Name;
                                TabPageItem.Tag = Page;
                                Page.Interface.Dock = DockStyle.Fill;

                                //Add
                                TabPages.Add(TabPageItem);
                            }
                        }
                    }

                //Handle Menu Buttons
                foreach (KeyValuePair<string, List<string>> collection in Factory.MenuButtons)
                    foreach (var typeName in collection.Value)
                    {
                        //Get Interface
                        IMenuButton MenuButton = Factory.CreateInstance<IMenuButton>(collection.Key, typeName);

                        //Check
                        if (MenuButton != null)
                        {
                            //Check Abide Version
                            if (MenuButton.MapVersion == MapVersion.Halo_2b && Classes.AbideAddOnManager.VersionMatch(MenuButton))
                            {
                                //Write
                                Console.WriteLine("Initializing Menu Button: {0}...", typeName);
                                InitTime = DateTime.Now;

                                //Initialize
                                try { MenuButton.Initialize(Manager); }
                                catch (Exception ex) { ReportAddOnError(MenuButton, ex, "INITIALZE"); }
                                MenuButton.NameChanged += AddOn_PropertyChanged;
                                MenuButton.IconChanged += AddOn_PropertyChanged;
                                MenuButton.DescriptionChanged += AddOn_PropertyChanged;

                                //Write
                                Console.WriteLine("Complete! ({0}ms)", (DateTime.Now - InitTime).Milliseconds);

                                //Add
                                AddOns.Add(MenuButton);
                                MenuButtonCount++;

                                //Create
                                ToolStripButton Button = new ToolStripButton(MenuButton.Name);
                                Button.ToolTipText = string.Format("{0} v{1} by {2}\r\n{3}", MenuButton.Name, MenuButton.Version, MenuButton.Author, MenuButton.Description);
                                Button.Image = MenuButton.Icon;
                                Button.Click += Button_Click;
                                Button.Tag = MenuButton;
                                MetaToolStrip.Items.Add(Button);
                            }
                        }
                    }
            }

            //Setup
            ToolCountLabel.Text = string.Format("Tool Count: {0}", ToolCount);
            TabPageCountLabel.Text = string.Format("Tab Page Count: {0}", TabPageCount);
            MenuButtonCountLabel.Text = string.Format("Menu Button Count: {0}", MenuButtonCount);

            //Resume
            ResumeLayout();
        }

        private void AddOn_PropertyChanged(object sender, EventArgs e)
        {
            if (sender is ITool)
            {
                foreach (ToolStripItem menuItem in ToolsDropdownButton.DropDownItems)
                    if (menuItem.Tag == sender)
                    {
                        menuItem.Text = ((ITool)sender).Name;
                        menuItem.Image = ((ITool)sender).Icon;
                        menuItem.ToolTipText = string.Format("{0} v{1} by {2}\r\n{3}", ((ITool)sender).Name, ((ITool)sender).Version,
                            ((ITool)sender).Author, ((ITool)sender).Description);
                    }
            }
            else if (sender is IMenuButton)
            {
                foreach (ToolStripItem menuItem in MetaToolStrip.Items)
                    if (menuItem.Tag == sender)
                    {
                        menuItem.Text = ((IMenuButton)sender).Name;
                        menuItem.Image = ((IMenuButton)sender).Icon;
                        menuItem.ToolTipText = string.Format("{0} v{1} by {2}\r\n{3}", ((IMenuButton)sender).Name, ((IMenuButton)sender).Version,
                            ((IMenuButton)sender).Author, ((IMenuButton)sender).Description);
                    }
            }
            else if (sender is ITabPage)
                foreach (TabPage tabPage in TabPages)
                    if (tabPage.Tag == sender)
                        tabPage.Text = ((ITabPage)sender).Name;
        }
        private void ToolItem_Click(object sender, EventArgs e)
        {
            //Suspend
            SuspendLayout();

            //Get ToolStripButton from Sender
            if (sender is ToolStripMenuItem)
            {
                //Get
                ToolStripMenuItem ToolItem = sender as ToolStripMenuItem;

                //Check Tag
                if (ToolItem.Tag is ITool)
                {
                    //Get Tool
                    ITool tool = ToolItem.Tag as ITool;
                    tool.Interface.Dock = DockStyle.Fill;

                    //Clear
                    MetaPanel.Controls.Clear();
                    MetaPanel.Controls.Add(tool.Interface);
                }
            }

            //Resume
            ResumeLayout();
        }
        private void Button_Click(object sender, EventArgs e)
        {
            //Get ToolStripButton from Sender
            if (sender is ToolStripButton)
            {
                //Get
                ToolStripButton Button = sender as ToolStripButton;

                //Check Tag
                if (Button.Tag is Abide_AddOn_API.Interfaces.IMenuButton)
                {
                    //Throw Event
                    Abide_AddOn_API.Interfaces.IMenuButton MenuButton = Button.Tag as Abide_AddOn_API.Interfaces.IMenuButton;
                    MenuButton.Click();
                }
            }
        }
        private void HistoryItem_Click(object sender, EventArgs e)
        {
            Forms.HistoryForm HistoryForm = new Forms.HistoryForm(Map.IO.GetHistory());
        }
        private void ReportAddOnError(IAddOn addOn, Exception ex, string eventName)
        {
            //Display String
            string displayText = string.Format("{0}: {1}", addOn.GetType().ToString(), eventName);

            //Create Button
            ToolStripMenuItem ErrorItem = new ToolStripMenuItem(displayText, Properties.Resources.Error);
            ErrorItem.Tag = new AddOnException(ex, addOn, ex.Message, eventName);
            ErrorItem.Click += ErrorItem_Click;

            //Add
            ErrorsDropDownButton.DropDownItems.Add(ErrorItem);

            //Show?
            ErrorsDropDownButton.Text = string.Format("({0})", ErrorsDropDownButton.DropDownItems.Count);
            ErrorsDropDownButton.Visible = ErrorsDropDownButton.HasDropDownItems;
        }
        private void ErrorItem_Click(object sender, EventArgs e)
        {
            //Prepare
            AddOnException ex = null;

            //Throw
            if (sender is ToolStripMenuItem)
            {
                ToolStripMenuItem Item = (ToolStripMenuItem)sender;
                if (Item.Tag != null && Item.Tag is AddOnException)
                    ex = ((AddOnException)Item.Tag);
            }

            //Check
            if (ex != null)
                new Forms.ErrorDialog(ex).ShowDialog();
        }
    }
}
